#include <Arduino.h>
#include <SPI.h>
#include <EEPROM.h>
#include <WiFi.h>
#include <ArduinoJson.h>

#include <MAX31865/MyTemperature.h>
#include <Button/MyButton.h>

#include "MQTT/MyMQTT.h"
#include "MAX31865/MyFit.h"
#include "MyEEPROM/MySetting.h"

#define BUTTON_PIN 0

//传感器整列
MyTemperature *my;

//OLED显示器
MyDisplay *display;

//按钮
MyButton *button;

///温度传感器参数//////
MySetting *myEEPROM;
CalibratePoint *calibratePoint;
uint16_t RAW[SENSER_QUANTITY];
double TEMPERATURE[SENSER_QUANTITY];

////MQTT网络//////
WiFiClient espClient;
PubSubClient client(espClient);
MyMQTT *myMQTT;              //MQ初始化
char msg[512];               //缓冲
StaticJsonDocument<512> doc; //JSON

void callback(char *topic, byte *payload, unsigned int length) //MQTT接收用
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

//////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  Serial.begin(115200);

  myEEPROM = new MySetting();

  // ///////////////////温度探头/////////////////////////////
  // /* Initialize SPI communication. */
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  SPI.setDataMode(SPI_MODE3);
  /* Allow the MAX31865 to warm up. */
  delay(100);

  my = new MyTemperature();
  my->calibratePoint = myEEPROM->readAll(); //读取参数（一定要设置）

  //////debug 输出参数/////
  for (size_t j = 0; j < SENSER_QUANTITY; j++)
  {
    Serial.printf("  S%d\n", j);
    Serial.print("raw=");
    for (size_t i = 0; i < 10; i++)
    {
      Serial.printf("%d,", my->calibratePoint[j].raw[i]);
    }
    Serial.println();
    Serial.print("t=");
    for (size_t i = 0; i < 10; i++)
    {
      Serial.printf("%5.2lf,", my->calibratePoint[j].t[i]);
    }
    Serial.println();
    Serial.print("p=");
    for (size_t i = 0; i < 3; i++)
    {
      Serial.printf("%6lf,", my->calibratePoint[j].parameter[i]);
    }
    Serial.println();
  }
  ///////////

  //////////////OLED显示屏//////////////////
  display = new MyDisplay();
  display->welcome();

  ///////////////按钮中断//////////////////////////////
  ///按钮中断必须在SPI后面初始化，原因未知
  ///ESP32有上拉下拉的脚不多，要预先查一下
  button = new MyButton();
  ////////////

  //////////MyMQTT用于初始化////////
  client.setCallback(callback);
  myMQTT = new MyMQTT(client);
}

void loop()
{
  ///////////////获取温度//////////////////////////////////
  for (size_t i = 0; i < SENSER_QUANTITY; i++)
  {
    uint16_t raw = my->getRawResistance(i);
    double t = my->getTemperature(raw, i);

    /////////////////////////////////
    //缓存
    RAW[i] = raw;
    TEMPERATURE[i] = t;

    //发送到显示模块
    display->setData(i, raw, t);
  }

  display->display(button->getMode()); //显示
  Serial.print("raw=");
  for (int i = 0; i < SENSER_QUANTITY; i++)
  {
    Serial.printf("%u,", RAW[i]);
  }
  Serial.println();

  ///////////MQTT发送到服务器//////////////////
  if (!client.connected())
  {
    myMQTT->reconnect();
  }
  client.loop();
  doc.clear(); //清理(不清理，很快就满了输出全null)
  doc["deviceId"] = myMQTT->mac;
  doc["module"] = "temperature";
  JsonArray jsonArray = doc.createNestedArray("data");
  for (size_t i = 0; i < SENSER_QUANTITY; i++)
  {
    jsonArray.add(round(TEMPERATURE[i])); //四舍五入
  }
  serializeJson(doc, msg);
  client.publish(myMQTT->topic, msg);
  Serial.print("MQTT send:");
  Serial.println(msg);

  ///////////////////////按键响应//////////////////////////////////////////
  /////温度校准点间隔要超过10度
  int modeTemp = button->getMode();
  for (size_t i = 0; i < 30; i++) //30×100ms=3s,缩短按键后屏幕相应时间
  {
    int mode = button->getMode();
    //任意按钮按下后响应
    if (modeTemp != mode || button->isSetButtonPressed() || button->increaseCount > 0 || button->decreaseCount > 0) //状态改变，或者设定钮按下
    {
      switch (mode)
      {
      case MyDisplay::MODE_SET_OTHER: //设置
        if (button->isSetButtonPressed())
        {
          double t = display->otherTemperature;
          Serial.printf("set temperature=%5.2lf\n", t);

          my->recalulateAndSetCelibrate(t, RAW);

          myEEPROM->writeAll(); //全部写入
        }

        if (button->increaseCount > 0)
        {
          display->otherTemperature += button->increaseCount * 0.1; //每次增加0.1度
          button->increaseCount = 0;                                //归零
        }

        if (button->decreaseCount > 0)
        {
          display->otherTemperature -= button->decreaseCount * 0.1; //每次减少0.1度
          button->decreaseCount = 0;                                //归零
        }
        break;

      case MyDisplay::MODE_END:
        button->setMode(MyDisplay::MODE_RUN); // 设置结束，返回运行状态
        display->otherTemperature = -300;     //清理
        break;
      }

      button->resetSetButton(); //确保只响应一次
      break;                    //提前结束3秒一次的等待
    }
    else
    { //无事发生，休眠0.1秒
      delay(100);
    }
  }
}
